#include "qtdbusinterfacelocation.h"

#include <private/qdbusconnection_p.h>

QtDBusInterfaceLocation::QtDBusInterfaceLocation(const QStringList &nodes, const void *self) : d{nodes, self}
{
}

bool QtDBusInterfaceLocation::isVaild() const
{
    return d.self;
}

QString QtDBusInterfaceLocation::path() const
{
    if (d.nodes.isEmpty())
        return {};
    return d.nodes.join('/').mid(1);
}

QString QtDBusInterfaceLocation::name() const
{
    if (!d.self)
        return {};
    return static_cast<const QDBusConnectionPrivate::ObjectTreeNode *>(d.self)->interfaceName;
}

QObject *QtDBusInterfaceLocation::object() const
{
    if (!d.self)
        return nullptr;
    return static_cast<const QDBusConnectionPrivate::ObjectTreeNode *>(d.self)->obj;
}

int QtDBusInterfaceLocation::flags() const
{
    if (!d.self)
        return 0;
    return static_cast<const QDBusConnectionPrivate::ObjectTreeNode *>(d.self)->flags;
}

QtDBusInterfaceLocation QtDBusInterfaceLocation::locationOf(const QObject *object, const QDBusConnection &connection)
{
    return locationOf(object, QDBusConnectionPrivate::d(connection));
}

QtDBusInterfaceLocation QtDBusInterfaceLocation::locationOf(const QObject *object, const QDBusConnectionPrivate *connectionSelf)
{
    const std::function<QtDBusInterfaceLocation(const QObject *, const QDBusConnectionPrivate::ObjectTreeNode &)> findNode =
        [&findNode](const QObject *object, const QDBusConnectionPrivate::ObjectTreeNode &parent) -> QtDBusInterfaceLocation {
        if (!parent.isActive())
            return {};

        if (parent.obj == object)
            return {{parent.name}, &parent};

        for (const QDBusConnectionPrivate::ObjectTreeNode &child : parent.children) {
            QtDBusInterfaceLocation &&location = findNode(object, child);
            if (!location.isVaild())
                continue;
            location.d.nodes.prepend(parent.name);
            return location;
        }
        return {};
    };

    QtDBusInterfaceLocation &&location = findNode(object, connectionSelf->rootNode);
    return location;
}
